package aliyun

import (
	"crypto/md5"
	"dmsv/common"
	"dmsv/etc"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
	"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
	"github.com/beego/beego/v2/core/logs"
	"time"
)

var (
	gTtsSavePath string

	gtoken     token
	accessId   string
	accessKey  string
	gResetChan chan bool
)

const (
	appKey = "6C9wkyxmWp9vLE8t"
)

//{"ErrMsg":"","Token":{"UserId":"1431767560165306","Id":"e28ff360b3434270946fdb5838ad4228","ExpireTime":1633111005}}
type token struct {
	UserId     string `json:"UserId"`
	Id         string `json:"Id"`
	ExpireTime int64  `json:"ExpireTime"`
	expire     time.Time
}

type tokenResp struct {
	ErrMsg string `json:"ErrMsg"`
	Token  token  `json:"Token"`
}

func getToken() string {

	if len(gtoken.Id) == 0 {
		renewToken()
	}

	return gtoken.Id
}

func updateTokenRoutine(resetChan chan bool) {

	logs.Debug("aliyun token 更新线程启动 >>>>>>>>>")

	go func() {

		for {
			select {
			case <-resetChan:

				if !gtoken.expire.IsZero() && time.Since(gtoken.expire) < -5*time.Hour {

					time.Sleep(10 * time.Second)
					renewToken()
					continue
				}

				client, err := sdk.NewClientWithAccessKey("cn-shanghai", accessId, accessKey)
				if err != nil {
					logs.Error("create client err:%v", err)
					time.Sleep(10 * time.Second)
					renewToken()
					continue
				}

				request := requests.NewCommonRequest()
				request.Method = "POST"
				request.Domain = "nls-meta.cn-shanghai.aliyuncs.com"
				request.ApiName = "CreateToken"
				request.Version = "2019-02-28"
				response, err := client.ProcessCommonRequest(request)
				if err != nil {
					logs.Error("common request err:%v", err)
					time.Sleep(5 * time.Second)
					renewToken()
					continue
				}

				result := &tokenResp{}
				err = json.Unmarshal(response.GetHttpContentBytes(), result)
				if err != nil || response.GetHttpStatus() != 200 {
					logs.Error("token 获取结果解析失败:%v,http状态：%v,内容:v%v.", err,
						response.GetHttpStatus(), response.GetHttpContentString())
					renewToken()
					continue
				}

				gtoken = result.Token

				gtoken.expire = time.Unix(gtoken.ExpireTime, 0)
				logs.Debug("请求token 返回:%v,token:%v,expir:%v,剩余有效:%4v ",
					response.GetHttpStatus(), response.GetHttpContentString(),
					gtoken.expire.Format("2006-01-02 15:04:05"),
					time.Since(gtoken.expire))

				time.AfterFunc(8*time.Hour, renewToken)
			}
		}
	}()
}

func Init() {

	accessId = etc.Conf.Storage.SecretId
	accessKey = etc.Conf.Storage.SecretKey

	gTtsSavePath = etc.Conf.Base.TtsPath

	ossInit(accessId, accessKey)

	gResetChan = make(chan bool, 10)

	gResetChan <- true
	updateTokenRoutine(gResetChan)
}

func hashString(text string) string {

	signByte := []byte(text)
	hash := md5.New()
	hash.Write(signByte)
	return hex.EncodeToString(hash.Sum(nil))
}

func TtsCache(text, voice, speed, pitch string) (string, bool) {

	hashStr := fmt.Sprintf("%v:%v:%v:%v", text, voice, speed, pitch)
	fileName := hashString(hashStr) + ".wav"

	filePath := gTtsSavePath + fileName
	if common.FileIsExist(filePath) {
		return filePath, true
	} else {
		return fileName, false
	}
}

func renewToken() {

	go func() {
		gResetChan <- true
	}()
}
